#! usr/bin/python

# -*- coding: utf-8 -*-


from parsers import parser_H2, KEGG_parser
import subprocess
from core import clustering as clust, objects as obj, processing as proc
from PyQt4 import QtGui, QtCore
import sys
import operator
import os.path as path



class identification_peaks(QtCore.QObject):
	"""
	launching the formula generator
	and compare to the databases
	"""
	
	def __init__(self, peaks, mmu, charge, alphabet, databases, data,  table_id):
		"""Simple Constructor"""
		QtCore.QObject.__init__(self)
		
		if not isinstance (peaks, obj.RawPeakList):
			raise TypeError, "masses must be a list object, ", type(peaks)

		self.peaks = peaks #list of masses -->to see if it's better to get only one mass 
		
		self.mmu =mmu
		self.charge =charge
		self.alphabet= alphabet
		self.databases= databases
		self.data = data #number of each element
		self.table_id = table_id#QtGui.QStandardItemModel(1,2)#table_id
		
		#name of used program
		if sys.platform =='win32':
			self.HR2 = path.normcase("config/HR2_ratios_modified.exe")#C:\Users\Marco\Desktop\msapipe\***********changed!
		else: 
			self.HR2 = "wine hr2_all_res"
			
		self.output_file = "HR2_output.txt" #TODO not create a file but juste take the output of the program
		
		self.url_jp = QtCore.QUrl("http://www.genome.jp/dbget-bin/www_bget?cpd:")
		
		
	def hr2_exe (self, mass, data):
		line =""
		for key in sorted(data):
			sub = "-"+str(key)+" "+str(data[key])+" "
			line+=sub
		line+= "> "
		cmdline = self.HR2+ " -m "+str(mass)+" "+"-t "+str(self.mmu)+" "+line + self.output_file #self.output_file" -C 1-95 -H 1-190 -N 0-20 -O 1-80 -P 0-12 -S 0-9 > "
		print cmdline
		process = subprocess.Popen(cmdline.split('\s'), shell =True, stdout =subprocess.PIPE)
		process.wait()
	
	
	def isotopic_pattern_comparison (self,formula, peak, error):
		calc_pattern = proc.PatternCalculation(formula)
		obs_pattern = []
		#first, calculate cumulated intensity
		cum_intensity = 0.
		for iso in peak.get_iso_cluster()._gen_peaks():
			cum_intensity += iso.get_area()
			
		for iso in peak.get_iso_cluster()._gen_peaks():
			obs_pattern.append((iso.get_area() / cum_intensity))#*100
			
		if len(calc_pattern) >= len(obs_pattern):#supposed to be always true
			#valid =True
			#formula score sum of difference
			score =0.
			for i, value in enumerate (obs_pattern):
				score += pow(value - calc_pattern[i], 2)
			formula.set_score(score)
		
		
	
	
	def recursive_fragment_checking(self, peak):
		""""
		Fonction for checking presence of  P, O, from deducting fragments
		implementing recursivity could be a good thing 
		"""
		
		nP =1; nOH =0; OH_list =[]; P_list =[]
		if not peak.get_frag_cluster():
			return max(P_list), max(OH_list)
		else:
			for frag in peak.get_frag_cluster():
				diff = abs(peak.get_trans_prec() - fragment.get_trans_prec())
				if diff == 80.:
					nP +=1
				if diff == 18.:
					nOH+=1
					recursive_fragment_checking(frag)
	
	
	def fragment_checking(self, peak):
		"""
		iterative checking
		"""
		
		#library_mass =[18., 44.,80., 70., 68., 60., 59., 46., 45., 35., 32., 28., 17., 16., 14.]
		lst_P =[]; lst_OH =[]
		nP=1; nOH =0 #by default one phosphate
		for fragment in peak.get_frag_cluster()._gen_peaks():
			#while fragment.get_frag_cluster():
			diff = abs(peak.get_trans_prec() - fragment.get_trans_prec())
			if diff == 80. :
				nP+=1
			if diff == 18.:
				nOH+=1
				#fragment= fragment.get_frag_cluster()
			#lst_P.append(nP)
			#lst_OH.append(nOH)
		#number of P found
		perso_data =dict(self.data)
		perso_data["P"] = ('-').join([str(nP), perso_data["P"].split('-')[1]])
		#perso_data["P"] =str(nP) +'-'+str(nP) #max(lst_P)
		#minimal number of O and H
		range_O = perso_data["O"].split('-')
		range_H = perso_data["H"].split('-')
		if float(range_O[0]) < nOH :
			range_O [0] = str(nOH) #max(lst_OH)
			range_H[0] = str(nOH) #max (lst_OH)
			perso_data["O"] = "-".join ( range_O)
			perso_data["H"] = "-".join (range_H)
		
		return perso_data
			
	def identification (self, hit, error =0.02):
		"""Main Function"""
		# error in percent; this will allow the comparison between
		#pb.setValue(0.)
		count =0.; line = 0
			
		for peak in self.peaks._gen_peaks():
			count += 1.
			#changes data values
			data = self.fragment_checking(peak)
			
			#launch formula generator
			self.hr2_exe(peak.get_trans_prec() + self.charge,  data)
			
			#parsing of the result file (add test for existing file)
			parser = parser_H2.parser_H2(self.output_file, peak.get_trans_prec())#self.output_file
			#get formulas
			formulas = parser.parsing(self.alphabet)
			
			#Apply Fiehn's Seven Golden Rules
			filtered_formula =[]
			for formula in formulas:
				#1 Isotopic Pattern Filter (the two previous steps have been done with the formula generator)
				self.isotopic_pattern_comparison(formula, peak, error)
				#3 idms
				#if peak.idms():
				#	if proc.idms_filter( abs(peak.idms().get_trans_prec() - peak.get_trans_prec()) ,formula):
				#		filtered_formula.append(formula)
				#4 Databases 
				l_kegg_, l_met_jp, l_biocyc = self.search_in_database(formula.toString())
				#4 SMILES
				
			#sorting by score
			formulas.sort(key =operator.attrgetter('score'))
			#take only the ten first matching
			i=0
			while i < len(formulas) and i < hit:# :
					filtered_formula.append(formulas[i])
					i+=1
					
			for formula in filtered_formula:
				#handles the output:  table mass versus formulas with link
				#self.isotopic_pattern_comparison(formula, peak, error)
				self.table_id.setItem(line, 0, QtGui.QStandardItem(str(peak.get_rt())))
				self.table_id.setItem(line, 1, QtGui.QStandardItem(str(formula.get_mass()+self.charge)))
				self.table_id.setItem(line, 2, QtGui.QStandardItem(str(self.mmu)))
				self.table_id.setItem(line, 3, QtGui.QStandardItem(formula.toString()))
				self.table_id.setItem(line, 4, QtGui.QStandardItem(str(formula.get_score())))#formula.get_score()
				
				#databases search
				l_kegg_, l_met_jp, l_biocyc = self.search_in_database(formula.toString())
				url =""; met_jp_test ="";names_kegg ="";names_met_jp=""

				#first kegg
				if l_kegg_:
					for data in l_kegg_:
						url += self.url_jp.toString()+data["ENTRY"]+"\n"
						if "NAME" in data.keys():
							names_kegg += data["NAME"]+"\n"

				else: 
					url+="Not Found"
					
				self.table_id.setItem(line, 5, QtGui.QStandardItem(url))
				self.table_id.setItem(line, 6, QtGui.QStandardItem(names_kegg))

				#prevent some bugs...with corrupted compound (without formula)
				
				#second metJP
				if l_met_jp:
					met_jp_test += "found"
				else: 
					met_jp_test += "not found"
				self.table_id.setItem(line, 7, QtGui.QStandardItem(met_jp_test))
				for data in l_met_jp:
					if "NAME" in data.keys():
						names_met_jp += data["NAME"]+"\n"
						
				self.table_id.setItem(line, 8, QtGui.QStandardItem(names_met_jp))
				
				self.setNonEditable()
				#self.formula_header.append(test)
				line+=1
			line+=1
			#pb.setValue((count/len(self.peaks))*100)
			value = (count/len(self.peaks))*100
			self.emit(QtCore.SIGNAL("update_pb"), value)
			
	
	def setNonEditable(self):
		for i in xrange (self.table_id.rowCount()):
			for j in xrange (self.table_id.columnCount()):
				self.table_id.item(i, j).setEditable(False)
				
			
	def search_in_database(self, formula):
		"""
		get matching formula
		"""
		l_kegg_ =[]; l_met_jp =[]; l_biocyc=[]
		
		#first kegg database
		if self.databases["KEGG"]:
			for data in self.databases["KEGG"]:
				if data["FORMULA"] ==formula:
					l_kegg_.append (data)
					#kegg_ = data
		
		#second metjp database
		if self.databases["METJP"]:
			for data in self.databases["METJP"]:
				if data["FORMULA"] == formula:
					l_met_jp.append(data)
					#met_jp =data		
		
		
		if self.databases["BIOCYC"]:
			for data in self.databases["BIOCYC"]:
				if data["FORMULA"] == formula:
					l_biocyc.append(data)
				
		return l_kegg_ , l_met_jp, l_biocyc
